package transport

import (
	"fmt"
	"net"
)

type ClientUDP struct {
	host string
	port int
	pc   *net.UDPConn

	readFunc PacketReadFunc
}

func NewClientUDP(host string, port int, readFunc PacketReadFunc) *ClientUDP {
	u := &ClientUDP{
		host:     host,
		port:     port,
		readFunc: readFunc,
	}

	return u
}

func (u *ClientUDP) Open() error {
	var (
		host = u.host
		port = u.port
	)

	conn, err := net.DialUDP("udp4", nil, &net.UDPAddr{
		IP:   net.ParseIP(host),
		Port: port,
	})
	if err != nil {
		return err
	}

	if err = conn.SetReadBuffer(UdpKernelReadBufferSize); err != nil {
		_ = conn.Close()
		return err
	}

	u.pc = conn

	go u.run()

	return nil
}

func (u *ClientUDP) Write(b []byte) (int, error) {
	if u == nil || u.pc == nil {
		return 0, fmt.Errorf("net not open")
	}

	return u.pc.Write(b)
}

func (u *ClientUDP) Close() {
	if u != nil && u.pc != nil {
		_ = u.pc.Close()
	}
}

func (u *ClientUDP) run() {
	for {
		buf := make([]byte, UdpMaxPayloadSize+1)
		n, addr, err := u.pc.ReadFrom(buf)
		if err != nil {
			return
		}
		_ = addr

		u.readFunc(buf[:n])
	}
}
